

package io.lkt.modules.sys.controller;


import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import io.lkt.common.annotation.SysLog;
import io.lkt.common.redis.RedisCacheUtil;
import io.lkt.common.utils.R;
import io.lkt.modules.sys.entity.SysUserEntity;
import io.lkt.modules.sys.nopassword.NoPwdToken;
import io.lkt.modules.sys.nopassword.NoPwdUtils;
import io.lkt.modules.sys.qrcode.QRCodeUtil;
import io.lkt.modules.sys.service.SysUserService;
import io.lkt.modules.sys.shiro.ShiroUtils;
import jodd.util.StringUtil;
import org.apache.ibatis.annotations.Param;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
 * 登录相关
 *
 * @author xss dustwas@163.com
 */
@Controller
public class SysLoginController extends AbstractController {
    @Autowired
    private Producer producer;

    @Autowired
    RedisCacheUtil redisCacheUtil;

    @Autowired
    private SysUserService sysUserService;

    @SysLog("验证码")
    @RequestMapping("captcha.jpg")
    public void captcha(HttpServletResponse response) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //生成文字验证码
        String text = producer.createText();
        //生成图片验证码
        BufferedImage image = producer.createImage(text);
        //保存到shiro session
        ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
    }

    /**
     * 登录
     */
    @SysLog("登录")
    @ResponseBody
    @RequestMapping(value = "/sys/login", method = RequestMethod.POST)
    public R login(String username, String password, String captcha) {
        String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
        if (!captcha.equalsIgnoreCase(kaptcha)) {
            return R.error("验证码不正确");
        }

        try {
            Subject subject = ShiroUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            subject.login(token);
        } catch (UnknownAccountException e) {
            return R.error(e.getMessage());
        } catch (IncorrectCredentialsException e) {
            return R.error("账号或密码不正确");
        } catch (LockedAccountException e) {
            return R.error("账号已被锁定,请联系管理员");
        } catch (AuthenticationException e) {
            return R.error("账户验证失败");
        }

        return R.ok();
    }

    /**
     * 退出
     */
    @RequestMapping(value = "logout", method = RequestMethod.GET)
    public String logout() {
        ShiroUtils.logout();
        return "redirect:login.html";
    }

    /**
     * 免密登录
     */
    @ResponseBody
    @RequestMapping(value = "/sys/loginNoCode", method = RequestMethod.POST)
    public R loginNoCode(String username) {
        if (StringUtil.isBlank(username)) {
            return R.error("用户名不能为空");
        }

        try {
            Subject subject = ShiroUtils.getSubject();
            // 使用自定义Token
            NoPwdToken ssoToken = new NoPwdToken(username);
            subject.login(ssoToken);
        } catch (UnknownAccountException e) {
            return R.error(e.getMessage());
        } catch (IncorrectCredentialsException e) {
            return R.error("账号或密码不正确");
        } catch (LockedAccountException e) {
            return R.error("账号已被锁定,请联系管理员");
        } catch (AuthenticationException e) {
            return R.error("账户验证失败");
        }

        return R.ok();
    }

    /**
     * 轮询免密登录
     */
    @SysLog("扫码登录")
    @ResponseBody
    @RequestMapping(value = "/sys/loginPool", method = RequestMethod.POST)
    public R loginPool(HttpServletRequest request) {

        // 获取 session
        HttpSession session = request.getSession();
        String uuid = (String) session.getAttribute(NoPwdUtils.LOGIN_UUID_SESSION_KEY);

//        System.out.println("loginPool uuid：" + uuid);
        String verifyKey = NoPwdUtils.LOGIN_QR_CODE_KEY + uuid;
        Object loginStatus = redisCacheUtil.getCacheObjectMaster(verifyKey);

        if (loginStatus != null) {
            String lastLoginStatus = (String) loginStatus;

//            System.out.println("loginPool lastLoginStatus：" + lastLoginStatus);

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_NOT)) {
                return R.error("等待扫码");
            }

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_HAS)) {
                return R.error("已扫码，等待确定");
            }

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_ONE)) {
                try {
//                    System.out.println("loginPool in" + lastLoginStatus);
                    Integer userId = Integer.valueOf(lastLoginStatus.replace(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_ONE, ""));
//                    System.out.println("loginPool on" + userId);
                    SysUserEntity user = (SysUserEntity) this.sysUserService.getByIdMaster(userId);
                    String userName = user.getUsername();
//                    System.out.println("loginPool userName" + userName);

                    Subject subject = ShiroUtils.getSubject();
                    // 使用自定义Token
                    NoPwdToken ssoToken = new NoPwdToken(userName);
                    subject.login(ssoToken);
                } catch (UnknownAccountException e) {
                    return R.error(e.getMessage());
                } catch (IncorrectCredentialsException e) {
                    return R.error("账号或密码不正确");
                } catch (LockedAccountException e) {
                    return R.error("账号已被锁定,请联系管理员");
                } catch (AuthenticationException e) {
                    return R.error("账户验证失败");
                }
                redisCacheUtil.removeSingleCacheMaster(verifyKey);
                return R.ok();
            }

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_TWO)) {
                try {
                    Integer userId = Integer.valueOf(lastLoginStatus.replace(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_TWO, ""));
                    SysUserEntity user = (SysUserEntity) this.sysUserService.getById(userId);
                    String userName = user.getUsername();
//                    System.out.println("loginPool userName" + userName);

                    Subject subject = ShiroUtils.getSubject();
                    // 使用自定义Token
                    NoPwdToken ssoToken = new NoPwdToken(userName);
                    subject.login(ssoToken);
                } catch (UnknownAccountException e) {
                    return R.error(e.getMessage());
                } catch (IncorrectCredentialsException e) {
                    return R.error("账号或密码不正确");
                } catch (LockedAccountException e) {
                    return R.error("账号已被锁定,请联系管理员");
                } catch (AuthenticationException e) {
                    return R.error("账户验证失败");
                }
                redisCacheUtil.removeSingleCacheMaster(verifyKey);
                return R.ok();
            }
        }
        return R.error("二维码已失效，点击二维码刷新");
    }

    @SysLog("获取登录二维码")
    @RequestMapping("loginQrCode.jpg")
    public void loginQrCode(@Param("origin") String origin, HttpServletResponse response, HttpServletRequest request) throws Exception {
        // 保存二维码信息
        String uuid = NoPwdUtils.simpleUUID();
//        uuid = "1781143d2db04ed681ee17bfd3ba1cb5";

        // 保存到 session
        HttpSession session = request.getSession();
        session.setAttribute(NoPwdUtils.LOGIN_UUID_SESSION_KEY, uuid);

        String verifyKey = NoPwdUtils.LOGIN_QR_CODE_KEY + uuid;

//        System.out.println("verifyKey: " + verifyKey);

        String text = null, imgPath = null;
        BufferedImage qrCodeImage = null;

        // 生成登录二维码
//        text = NoPwdUtils.WEB_PATH_MAIN + "?uniqueness=" + uuid + "&qrCodeType=login";
        text = NoPwdUtils.WEB_PATH_MAIN.replace("UNIQUENESS", uuid).replace("QRCODETYPE", NoPwdUtils.QR_CODE_TYPE_LOGIN).replace("ORIGIN", origin);
        qrCodeImage = QRCodeUtil.encodeReturnBufferedImage(text, imgPath, false);

        redisCacheUtil.setCacheObjectMaster(verifyKey, NoPwdUtils.QR_CODE_STATUS_NOT, NoPwdUtils.LOGIN_QR_CODE_EXPIRATION);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(qrCodeImage, "jpg", out);
    }

    @SysLog("获取绑定二维码")
    @RequestMapping("bindingQrCode.jpg")
    public void bindingQrCode(@Param("origin") String origin, @Param("sysUserId") Long sysUserId, HttpServletResponse response, HttpServletRequest request) throws Exception {
        // 保存二维码信息
        String uuid = NoPwdUtils.simpleUUID();
//        uuid = "1781143d2db04ed681ee17bfd3ba1cb5";

        // 保存到 session
        HttpSession session = request.getSession();
        session.setAttribute(NoPwdUtils.BINDING_UUID_SESSION_KEY, uuid);

        String verifyKey = NoPwdUtils.BINDING_QR_CODE_KEY + uuid;

//        System.out.println("verifyKey: " + verifyKey);

        String text = null, imgPath = null;
        BufferedImage qrCodeImage = null;

        if (sysUserId == null) {
            sysUserId = getUser().getUserId();
        }
        // 生成绑定二维码
//        text = NoPwdUtils.WEB_PATH_MAIN + "?uniqueness=" + uuid + "&qrCodeType=binding&sysUser=" + sysUserId;
        text = NoPwdUtils.WEB_PATH_MAIN.replace("UNIQUENESS", uuid).replace("QRCODETYPE", NoPwdUtils.QR_CODE_TYPE_BINDING).replace("SYSUSER", sysUserId.toString()).replace("ORIGIN", origin);
//        System.out.println("生成绑定二维码: " + text);
        qrCodeImage = QRCodeUtil.encodeReturnBufferedImage(text, imgPath, false);

        redisCacheUtil.setCacheObjectMaster(verifyKey, NoPwdUtils.QR_CODE_STATUS_NOT, NoPwdUtils.LOGIN_QR_CODE_EXPIRATION);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(qrCodeImage, "jpg", out);
    }

    /**
     * 轮询绑定
     */
    @ResponseBody
    @RequestMapping(value = "/sys/bindingPool", method = RequestMethod.POST)
    public R bindingPool(HttpServletRequest request) {
//        System.out.println("轮询绑定");
        // 获取 session
        HttpSession session = request.getSession();
        String uuid = (String) session.getAttribute(NoPwdUtils.BINDING_UUID_SESSION_KEY);

        String verifyKey = NoPwdUtils.BINDING_QR_CODE_KEY + uuid;
        Object loginStatus = redisCacheUtil.getCacheObjectMaster(verifyKey);

        if (loginStatus != null) {
            String lastLoginStatus = (String) loginStatus;

//            System.out.println("loginPool lastLoginStatus：" + lastLoginStatus);

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_NOT)) {
                return R.error("等待扫码");
            }

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_HAS)) {
                return R.error("已扫码，等待确定");
            }

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_ONE)) {
                Integer userId = Integer.valueOf(lastLoginStatus.replace(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_ONE, ""));
                SysUserEntity user = (SysUserEntity) this.sysUserService.getById(userId);

                redisCacheUtil.removeSingleCacheMaster(verifyKey);
                return R.ok();
            }

            if (lastLoginStatus.contains(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_TWO)) {
                Integer userId = Integer.valueOf(lastLoginStatus.replace(NoPwdUtils.QR_CODE_STATUS_OK_ORIGIN_TWO, ""));
                SysUserEntity user = (SysUserEntity) this.sysUserService.getById(userId);

                redisCacheUtil.removeSingleCacheMaster(verifyKey);
                return R.ok();
            }
        }
        return R.error("二维码已失效，点击二维码刷新");
    }

}
